Autogenerated HTML docs for 36de72aa9dc3b7daf8cf2770c840f39bb0d2ae70 
diff --git a/howto/isolate-bugs-with-bisect.txt b/howto/isolate-bugs-with-bisect.txt new file mode 100644 index 0000000..4009495 --- /dev/null +++ b/howto/isolate-bugs-with-bisect.txt 
@@ -0,0 +1,65 @@ +From:	Linus Torvalds <torvalds () osdl ! org> +To:	git@vger.kernel.org +Date:	2005-11-08 1:31:34 +Subject: Real-life kernel debugging scenario +Abstract: Short-n-sweet, Linus tells us how to leverage `git-bisect` to perform +	bug isolation on a repository where "good" and "bad" revisions are known +	in order to identify a suspect commit. + + +How To Use git-bisect To Isolate a Bogus Commit +=============================================== + +The way to use "git bisect" couldn't be easier. + +Figure out what the oldest bad state you know about is (that's usually the  +head of "master", since that's what you just tried to boot and failed at).  +Also, figure out the most recent known-good commit (usually the _previous_  +kernel you ran: and if you've only done a single "pull" in between, it  +will be ORIG_HEAD). + +Then do + +	git bisect start +	git bisect bad master	<- mark "master" as the bad state +	git bisect good ORIG_HEAD	<- mark ORIG_HEAD as good (or + whatever other known-good  + thing you booted laste) + +and at this point "git bisect" will churn for a while, and tell you what  +the mid-point between those two commits are, and check that state out as  +the head of the bew "bisect" branch. + +Compile and reboot. + +If it's good, just do + +	git bisect good	<- mark current head as good + +otherwise, reboot into a good kernel instead, and do (surprise surprise,  +git really is very intuitive): + +	git bisect bad	<- mark current head as bad + +and whatever you do, git will select a new half-way point. Do this for a  +while, until git tells you exactly which commit was the first bad commit.  +That's your culprit. + +It really works wonderfully well, except for the case where there was  +_another_ commit that broke something in between, like introduced some  +stupid compile error. In that case you should not mark that commit good or  +bad: you should try to find another commit close-by, and do a "git reset  +--hard <newcommit>" to try out _that_ commit instead, and then test that  +instead (and mark it good or bad). + +You can do "git bisect visualize" while you do all this to see what's  +going on by starting up gitk on the bisection range. + +Finally, once you've figured out exactly which commit was bad, you can  +then go back to the master branch, and try reverting just that commit: + +	git checkout master +	git revert <bad-commit-id> + +to verify that the top-of-kernel works with that single commit reverted. + 
diff --git a/howto/make-dist.txt b/howto/make-dist.txt new file mode 100644 index 0000000..00e330b --- /dev/null +++ b/howto/make-dist.txt 
@@ -0,0 +1,52 @@ +Date: Fri, 12 Aug 2005 22:39:48 -0700 (PDT) +From: Linus Torvalds <torvalds@osdl.org> +To: Dave Jones <davej@redhat.com> +cc: git@vger.kernel.org +Subject: Re: Fwd: Re: git checkout -f branch doesn't remove extra files +Abstract: In this article, Linus talks about building a tarball, + incremental patch, and ChangeLog, given a base release and two + rc releases, following the convention of giving the patch from + the base release and the latest rc, with ChangeLog between the + last rc and the latest rc. + +On Sat, 13 Aug 2005, Dave Jones wrote: +> +> > Git actually has a _lot_ of nifty tools. I didn't realize that people +> > didn't know about such basic stuff as "git-tar-tree" and "git-ls-files". +> +> Maybe its because things are moving so fast :) Or maybe I just wasn't +> paying attention on that day. (I even read the git changes via RSS, +> so I should have no excuse). + +Well, git-tar-tree has been there since late April - it's actually one of +those really early commands. I'm pretty sure the RSS feed came later ;) + +I use it all the time in doing releases, it's a lot faster than creating a +tar tree by reading the filesystem (even if you don't have to check things +out). A hidden pearl. + +This is my crappy "release-script": + + [torvalds@g5 ~]$ cat bin/release-script + #!/bin/sh + stable="$1" + last="$2" + new="$3" + echo "# git-tag v$new" + echo "git-tar-tree v$new linux-$new | gzip -9 > ../linux-$new.tar.gz" + echo "git-diff-tree -p v$stable v$new | gzip -9 > ../patch-$new.gz" + echo "git-rev-list --pretty v$new ^v$last > ../ChangeLog-$new" + echo "git-rev-list --pretty=short v$new ^v$last | git-shortlog > ../ShortLog" + echo "git-diff-tree -p v$last v$new | git-apply --stat > ../diffstat-$new" + +and when I want to do a new kernel release I literally first tag it, and +then do + + release-script 2.6.12 2.6.13-rc6 2.6.13-rc7 + +and check that things look sane, and then just cut-and-paste the commands. + +Yeah, it's stupid. + + Linus + 
diff --git a/howto/rebase-and-edit.txt b/howto/rebase-and-edit.txt new file mode 100644 index 0000000..646c55c --- /dev/null +++ b/howto/rebase-and-edit.txt 
@@ -0,0 +1,81 @@ +Date:	Sat, 13 Aug 2005 22:16:02 -0700 (PDT) +From:	Linus Torvalds <torvalds@osdl.org> +To:	Steve French <smfrench@austin.rr.com> +cc:	git@vger.kernel.org +Subject: Re: sending changesets from the middle of a git tree +Abstract: In this article, Linus demonstrates how a broken commit + in a sequence of commits can be removed by rewinding the head and + reapplying selected changes. + +On Sat, 13 Aug 2005, Linus Torvalds wrote: + +> That's correct. Same things apply: you can move a patch over, and create a  +> new one with a modified comment, but basically the _old_ commit will be  +> immutable. + +Let me clarify. + +You can entirely _drop_ old branches, so commits may be immutable, but +nothing forces you to keep them. Of course, when you drop a commit, you'll  +always end up dropping all the commits that depended on it, and if you  +actually got somebody else to pull that commit you can't drop it from  +_their_ repository, but undoing things is not impossible. + +For example, let's say that you've made a mess of things: you've committed +three commits "old->a->b->c", and you notice that "a" was broken, but you +want to save "b" and "c". What you can do is + +	# Create a branch "broken" that is the current code +	# for reference +	git branch broken + +	# Reset the main branch to three parents back: this  +	# effectively undoes the three top commits +	git reset HEAD^^^ +	git checkout -f + +	# Check the result visually to make sure you know what's +	# going on +	gitk --all + +	# Re-apply the two top ones from "broken" +	# +	# First "parent of broken" (aka b): +	git-diff-tree -p broken^ | git-apply --index +	git commit --reedit=broken^ + +	# Then "top of broken" (aka c): +	git-diff-tree -p broken | git-apply --index +	git commit --reedit=broken + +and you've now re-applied (and possibly edited the comments) the two +commits b/c, and commit "a" is basically gone (it still exists in the +"broken" branch, of course). + +Finally, check out the end result again: + +	# Look at the new commit history +	gitk --all + +to see that everything looks sensible. + +And then, you can just remove the broken branch if you decide you really  +don't want it: + +	# remove 'broken' branch +	git branch -d broken + +	# Prune old objects if you're really really sure +	git prune + +And yeah, I'm sure there are other ways of doing this. And as usual, the  +above is totally untested, and I just wrote it down in this email, so if  +I've done something wrong, you'll have to figure it out on your own ;) + +	Linus +- +To unsubscribe from this list: send the line "unsubscribe git" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html + + 
diff --git a/howto/rebase-from-internal-branch.txt b/howto/rebase-from-internal-branch.txt new file mode 100644 index 0000000..c2d4a91 --- /dev/null +++ b/howto/rebase-from-internal-branch.txt 
@@ -0,0 +1,165 @@ +From:	Junio C Hamano <junkio@cox.net> +To:	git@vger.kernel.org +Cc:	Petr Baudis <pasky@suse.cz>, Linus Torvalds <torvalds@osdl.org> +Subject: Re: sending changesets from the middle of a git tree +Date:	Sun, 14 Aug 2005 18:37:39 -0700 +Abstract: In this article, JC talks about how he rebases the + public "pu" branch using the core GIT tools when he updates + the "master" branch, and how "rebase" works. Also discussed + is how this applies to individual developers who sends patches + upstream. + +Petr Baudis <pasky@suse.cz> writes: + +> Dear diary, on Sun, Aug 14, 2005 at 09:57:13AM CEST, I got a letter +> where Junio C Hamano <junkio@cox.net> told me that... +>> Linus Torvalds <torvalds@osdl.org> writes: +>>  +>> > Junio, maybe you want to talk about how you move patches from your "pu"  +>> > branch to the real branches. +>>  +> Actually, wouldn't this be also precisely for what StGIT is intended to? + +Exactly my feeling. I was sort of waiting for Catalin to speak +up. With its basing philosophical ancestry on quilt, this is +the kind of task StGIT is designed to do. + +I just have done a simpler one, this time using only the core +GIT tools. + +I had a handful commits that were ahead of master in pu, and I +wanted to add some documentation bypassing my usual habit of +placing new things in pu first. At the beginning, the commit +ancestry graph looked like this: + + *"pu" head + master --> #1 --> #2 --> #3 + +So I started from master, made a bunch of edits, and committed: + + $ git checkout master + $ cd Documentation; ed git.txt ... + $ cd ..; git add Documentation/*.txt + $ git commit -s + +After the commit, the ancestry graph would look like this: + + *"pu" head + master^ --> #1 --> #2 --> #3 + \ + \---> master + +The old master is now master^ (the first parent of the master). +The new master commit holds my documentation updates. + +Now I have to deal with "pu" branch. + +This is the kind of situation I used to have all the time when +Linus was the maintainer and I was a contributor, when you look +at "master" branch being the "maintainer" branch, and "pu" +branch being the "contributor" branch. Your work started at the +tip of the "maintainer" branch some time ago, you made a lot of +progress in the meantime, and now the maintainer branch has some +other commits you do not have yet. And "git rebase" was written +with the explicit purpose of helping to maintain branches like +"pu". You _could_ merge master to pu and keep going, but if you +eventually want to cherrypick and merge some but not necessarily +all changes back to the master branch, it often makes later +operations for _you_ easier if you rebase (i.e. carry forward +your changes) "pu" rather than merge. So I ran "git rebase": + + $ git checkout pu + $ git rebase master pu + +What this does is to pick all the commits since the current +branch (note that I now am on "pu" branch) forked from the +master branch, and forward port these changes. + + master^ --> #1 --> #2 --> #3 + \ *"pu" head + \---> master --> #1' --> #2' --> #3' + +The diff between master^ and #1 is applied to master and +committed to create #1' commit with the commit information (log, +author and date) taken from commit #1. On top of that #2' and #3' +commits are made similarly out of #2 and #3 commits. + +Old #3 is not recorded in any of the .git/refs/heads/ file +anymore, so after doing this you will have dangling commit if +you ran fsck-cache, which is normal. After testing "pu", you +can run "git prune" to get rid of those original three commits. + +While I am talking about "git rebase", I should talk about how +to do cherrypicking using only the core GIT tools. + +Let's go back to the earlier picture, with different labels. + +You, as an individual developer, cloned upstream repository and +made a couple of commits on top of it. + + *your "master" head + upstream --> #1 --> #2 --> #3 + +You would want changes #2 and #3 incorporated in the upstream, +while you feel that #1 may need further improvements. So you +prepare #2 and #3 for e-mail submission. + + $ git format-patch master^^ master + +This creates two files, 0001-XXXX.txt and 0002-XXXX.txt. Send +them out "To: " your project maintainer and "Cc: " your mailing +list. You could use contributed script git-send-email if +your host has necessary perl modules for this, but your usual +MUA would do as long as it does not corrupt whitespaces in the +patch. + +Then you would wait, and you find out that the upstream picked +up your changes, along with other changes. + + where *your "master" head + upstream --> #1 --> #2 --> #3 + used \  + to be \--> #A --> #2' --> #3' --> #B --> #C + *upstream head + +The two commits #2' and #3' in the above picture record the same +changes your e-mail submission for #2 and #3 contained, but +probably with the new sign-off line added by the upsteam +maintainer and definitely with different committer and ancestry +information, they are different objects from #2 and #3 commits. + +You fetch from upstream, but not merge. + + $ git fetch upstream + +This leaves the updated upstream head in .git/FETCH_HEAD but +does not touch your .git/HEAD nor .git/refs/heads/master.  +You run "git rebase" now. + + $ git rebase FETCH_HEAD master + +Earlier, I said that rebase applies all the commits from your +branch on top of the upstream head. Well, I lied. "git rebase" +is a bit smarter than that and notices that #2 and #3 need not +be applied, so it only applies #1. The commit ancestry graph +becomes something like this: + + where *your old "master" head + upstream --> #1 --> #2 --> #3 + used \ your new "master" head* + to be \--> #A --> #2' --> #3' --> #B --> #C --> #1' + *upstream + head + +Again, "git prune" would discard the disused commits #1-#3 and +you continue on starting from the new "master" head, which is +the #1' commit. + +-jc + +- +To unsubscribe from this list: send the line "unsubscribe git" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html + + 
diff --git a/howto/rebuild-from-update-hook.txt b/howto/rebuild-from-update-hook.txt new file mode 100644 index 0000000..02621b5 --- /dev/null +++ b/howto/rebuild-from-update-hook.txt 
@@ -0,0 +1,87 @@ +Subject: [HOWTO] Using post-update hook +Message-ID: <7vy86o6usx.fsf@assigned-by-dhcp.cox.net> +From: Junio C Hamano <junkio@cox.net> +Date: Fri, 26 Aug 2005 18:19:10 -0700 +Abstract: In this how-to article, JC talks about how he + uses the post-update hook to automate git documentation page + shown at http://www.kernel.org/pub/software/scm/git/docs/. + +The pages under http://www.kernel.org/pub/software/scm/git/docs/ +are built from Documentation/ directory of the git.git project +and needed to be kept up-to-date. The www.kernel.org/ servers +are mirrored and I was told that the origin of the mirror is on +the machine $some.kernel.org, on which I was given an account +when I took over git maintainership from Linus. + +The directories relevant to this how-to are these two: + + /pub/scm/git/git.git/	The public git repository. + /pub/software/scm/git/docs/	The HTML documentation page. + +So I made a repository to generate the documentation under my +home directory over there. + + $ cd + $ mkdir doc-git && cd doc-git + $ git clone /pub/scm/git/git.git/ docgen + +What needs to happen is to update the $HOME/doc-git/docgen/ +working tree, build HTML docs there and install the result in +/pub/software/scm/git/docs/ directory. So I wrote a little +script: + + $ cat >dododoc.sh <<\EOF + #!/bin/sh + cd $HOME/doc-git/docgen || exit + + unset GIT_DIR + + git pull /pub/scm/git/git.git/ master && + cd Documentation && + make install-webdoc + EOF + +Initially I used to run this by hand whenever I push into the +public git repository. Then I did a cron job that ran twice a +day. The current round uses the post-update hook mechanism, +like this: + + $ cat >/pub/scm/git/git.git/hooks/post-update <<\EOF + #!/bin/sh + # + # An example hook script to prepare a packed repository for use over + # dumb transports. + # + # To enable this hook, make this file executable by "chmod +x post-update". + + case " $* " in + *' refs/heads/master '*) + echo $HOME/doc-git/dododoc.sh | at now + ;; + esac + exec git-update-server-info + EOF + $ chmod +x /pub/scm/git/git.git/hooks/post-update + +There are four things worth mentioning: + + - The update-hook is run after the repository accepts a "git + push", under my user privilege. It is given the full names + of refs that have been updated as arguments. My post-update + runs the dododoc.sh script only when the master head is + updated. + + - When update-hook is run, GIT_DIR is set to '.' by the calling + receive-pack. This is inherited by the dododoc.sh run via + the "at" command, and needs to be unset; otherwise, "git + pull" it does into $HOME/doc-git/docgen/ repository would not + work correctly. + + - The stdout of update hook script is not connected to git + push; I run the heavy part of the command inside "at", to + receive the execution report via e-mail. + + - This is still crude and does not protect against simultaneous + make invocations stomping on each other. I would need to add + some locking mechanism for this. + 
diff --git a/howto/revert-branch-rebase.html b/howto/revert-branch-rebase.html new file mode 100644 index 0000000..229728c --- /dev/null +++ b/howto/revert-branch-rebase.html 
@@ -0,0 +1,447 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"  + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">  +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">  +<head>  +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />  +<meta name="generator" content="AsciiDoc 7.0.1" />  +<style type="text/css">  +/* Debug borders */  +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 {  +/*  + border: 1px solid red;  +*/  +}  +  +body {  + margin: 1em 5% 1em 5%;  +}  +  +a { color: blue; }  +a:visited { color: fuchsia; }  +  +em {  + font-style: italic;  +}  +  +strong {  + font-weight: bold;  +}  +  +tt {  + color: navy;  +}  +  +h1, h2, h3, h4, h5, h6 {  + color: #527bbd;  + font-family: sans-serif;  + margin-top: 1.2em;  + margin-bottom: 0.5em;  + line-height: 1.3;  +}  +  +h1 {  + border-bottom: 2px solid silver;  +}  +h2 {  + border-bottom: 2px solid silver;  + padding-top: 0.5em;  +}  +  +div.sectionbody {  + font-family: serif;  + margin-left: 0;  +}  +  +hr {  + border: 1px solid silver;  +}  +  +p {  + margin-top: 0.5em;  + margin-bottom: 0.5em;  +}  +  +pre {  + padding: 0;  + margin: 0;  +}  +  +span#author {  + color: #527bbd;  + font-family: sans-serif;  + font-weight: bold;  + font-size: 1.2em;  +}  +span#email {  +}  +span#revision {  + font-family: sans-serif;  +}  +  +div#footer {  + font-family: sans-serif;  + font-size: small;  + border-top: 2px solid silver;  + padding-top: 0.5em;  + margin-top: 4.0em;  +}  +div#footer-text {  + float: left;  + padding-bottom: 0.5em;  +}  +div#footer-badges {  + float: right;  + padding-bottom: 0.5em;  +}  +  +div#preamble,  +div.tableblock, div.imageblock, div.exampleblock, div.verseblock,  +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,  +div.admonitionblock {  + margin-right: 10%;  + margin-top: 1.5em;  + margin-bottom: 1.5em;  +}  +div.admonitionblock {  + margin-top: 2.5em;  + margin-bottom: 2.5em;  +}  +  +div.content { /* Block element content. */  + padding: 0;  +}  +  +/* Block element titles. */  +div.title, caption.title {  + font-family: sans-serif;  + font-weight: bold;  + text-align: left;  + margin-top: 1.0em;  + margin-bottom: 0.5em;  +}  +div.title + * {  + margin-top: 0;  +}  +  +td div.title:first-child {  + margin-top: 0.0em;  +}  +div.content div.title:first-child {  + margin-top: 0.0em;  +}  +div.content + div.title {  + margin-top: 0.0em;  +}  +  +div.sidebarblock > div.content {  + background: #ffffee;  + border: 1px solid silver;  + padding: 0.5em;  +}  +  +div.listingblock > div.content {  + border: 1px solid silver;  + background: #f4f4f4;  + padding: 0.5em;  +}  +  +div.quoteblock > div.content {  + padding-left: 2.0em;  +}  +div.quoteblock .attribution {  + text-align: right;  +}  +  +div.admonitionblock .icon {  + vertical-align: top;  + font-size: 1.1em;  + font-weight: bold;  + text-decoration: underline;  + color: #527bbd;  + padding-right: 0.5em;  +}  +div.admonitionblock td.content {  + padding-left: 0.5em;  + border-left: 2px solid silver;  +}  +  +div.exampleblock > div.content {  + border-left: 2px solid silver;  + padding: 0.5em;  +}  +  +div.verseblock div.content {  + white-space: pre;  +}  +  +div.imageblock div.content { padding-left: 0; }  +div.imageblock img { border: 1px solid silver; }  +span.image img { border-style: none; }  +  +dl {  + margin-top: 0.8em;  + margin-bottom: 0.8em;  +}  +dt {  + margin-top: 0.5em;  + margin-bottom: 0;  + font-style: italic;  +}  +dd > *:first-child {  + margin-top: 0;  +}  +  +ul, ol {  + list-style-position: outside;  +}  +ol.olist2 {  + list-style-type: lower-alpha;  +}  +  +div.tableblock > table {  + border-color: #527bbd;  + border-width: 3px;  +}  +thead {  + font-family: sans-serif;  + font-weight: bold;  +}  +tfoot {  + font-weight: bold;  +}  +  +div.hlist {  + margin-top: 0.8em;  + margin-bottom: 0.8em;  +}  +td.hlist1 {  + vertical-align: top;  + font-style: italic;  + padding-right: 0.8em;  +}  +td.hlist2 {  + vertical-align: top;  +}  +  +@media print {  + div#footer-badges { display: none; }  +}  +/* Workarounds for IE6's broken and incomplete CSS2. */  +  +div.sidebar-content {  + background: #ffffee;  + border: 1px solid silver;  + padding: 0.5em;  +}  +div.sidebar-title, div.image-title {  + font-family: sans-serif;  + font-weight: bold;  + margin-top: 0.0em;  + margin-bottom: 0.5em;  +}  +  +div.listingblock div.content {  + border: 1px solid silver;  + background: #f4f4f4;  + padding: 0.5em;  +}  +  +div.quoteblock-content {  + padding-left: 2.0em;  +}  +  +div.exampleblock-content {  + border-left: 2px solid silver;  + padding-left: 0.5em;  +}  +</style>  +<title>Reverting an existing commit</title>  +</head>  +<body>  +<div id="header">  +<h1>Reverting an existing commit</h1>  +</div>  +<div id="preamble">  +<div class="sectionbody">  +<p>One of the changes I pulled into the <em>master</em> branch turns out to  +break building GIT with GCC 2.95. While they were well intentioned  +portability fixes, keeping things working with gcc-2.95 was also  +important. Here is what I did to revert the change in the <em>master</em>  +branch and to adjust the <em>pu</em> branch, using core GIT tools and  +barebone Porcelain.</p>  +<p>First, prepare a throw-away branch in case I screw things up.</p>  +<div class="listingblock">  +<div class="content">  +<pre><tt>$ git checkout -b revert-c99 master</tt></pre>  +</div></div>  +<p>Now I am on the <em>revert-c99</em> branch. Let's figure out which commit to  +revert. I happen to know that the top of the <em>master</em> branch is a  +merge, and its second parent (i.e. foreign commit I merged from) has  +the change I would want to undo. Further I happen to know that that  +merge introduced 5 commits or so:</p>  +<div class="listingblock">  +<div class="content">  +<pre><tt>$ git show-branch --more=4 master master^2 | head  +! [master] Merge refs/heads/portable from http://www.cs.berkeley....  + ! [master^2] Replace C99 array initializers with code.  +--  ++ [master] Merge refs/heads/portable from http://www.cs.berkeley....  +++ [master^2] Replace C99 array initializers with code.  +++ [master^2~1] Replace unsetenv() and setenv() with older putenv().  +++ [master^2~2] Include sys/time.h in daemon.c.  +++ [master^2~3] Fix ?: statements.  +++ [master^2~4] Replace zero-length array decls with [].  ++ [master~1] tutorial note about git branch</tt></pre>  +</div></div>  +<p>The <em>&#8212;more=4</em> above means "after we reach the merge base of refs,  +show until we display four more common commits". That last commit  +would have been where the "portable" branch was forked from the main  +git.git repository, so this would show everything on both branches  +since then. I just limited the output to the first handful using  +<em>head</em>.</p>  +<p>Now I know <em>master^2~4</em> (pronounce it as "find the second parent of  +the <em>master</em>, and then go four generations back following the first  +parent") is the one I would want to revert. Since I also want to say  +why I am reverting it, the <em>-n</em> flag is given to <em>git revert</em>. This  +prevents it from actually making a commit, and instead <em>git revert</em>  +leaves the commit log message it wanted to use in <em>.msg</em> file:</p>  +<div class="listingblock">  +<div class="content">  +<pre><tt>$ git revert -n master^2~4  +$ cat .msg  +Revert "Replace zero-length array decls with []."  +  +This reverts 6c5f9baa3bc0d63e141e0afc23110205379905a4 commit.  +$ git diff HEAD ;# to make sure what we are reverting makes sense.  +$ make CC=gcc-2.95 clean test ;# make sure it fixed the breakage.  +$ make clean test ;# make sure it did not cause other breakage.</tt></pre>  +</div></div>  +<p>The reverted change makes sense (from reading the <em>diff</em> output), does  +fix the problem (from <em>make CC=gcc-2.95</em> test), and does not cause new  +breakage (from the last <em>make test</em>). I'm ready to commit:</p>  +<div class="listingblock">  +<div class="content">  +<pre><tt>$ git commit -a -s ;# read .msg into the log,  + # and explain why I am reverting.</tt></pre>  +</div></div>  +<p>I could have screwed up in any of the above steps, but in the worst  +case I could just have done <em>git checkout master</em> to start over.  +Fortunately I did not have to; what I have in the current branch  +<em>revert-c99</em> is what I want. So merge that back into <em>master</em>:</p>  +<div class="listingblock">  +<div class="content">  +<pre><tt>$ git checkout master  +$ git resolve master revert-c99 fast ;# this should be a fast forward  +Updating from 10d781b9caa4f71495c7b34963bef137216f86a8 to e3a693c...  + cache.h | 8 ++++----  + commit.c | 2 +-  + ls-files.c | 2 +-  + receive-pack.c | 2 +-  + server-info.c | 2 +-  + 5 files changed, 8 insertions(+), 8 deletions(-)</tt></pre>  +</div></div>  +<p>The <em>fast</em> in the above <em>git resolve</em> is not a magic. I knew this  +<em>resolve</em> would result in a fast forward merge, and if not, there is  +something very wrong (so I would do <em>git reset</em> on the <em>master</em> branch  +and examine the situation). When a fast forward merge is done, the  +message parameter to <em>git resolve</em> is discarded, because no new commit  +is created. You could have said <em>junk</em> or <em>nothing</em> there as well.</p>  +<p>There is no need to redo the test at this point. We fast forwarded  +and we know <em>master</em> matches <em>revert-c99</em> exactly. In fact:</p>  +<div class="listingblock">  +<div class="content">  +<pre><tt>$ git diff master..revert-c99</tt></pre>  +</div></div>  +<p>says nothing.</p>  +<p>Then we rebase the <em>pu</em> branch as usual.</p>  +<div class="listingblock">  +<div class="content">  +<pre><tt>$ git checkout pu  +$ git tag pu-anchor pu  +$ git rebase master  +* Applying: Redo "revert" using three-way merge machinery.  +First trying simple merge strategy to cherry-pick.  +Finished one cherry-pick.  +* Applying: Remove git-apply-patch-script.  +First trying simple merge strategy to cherry-pick.  +Simple cherry-pick fails; trying Automatic cherry-pick.  +Removing Documentation/git-apply-patch-script.txt  +Removing git-apply-patch-script  +Finished one cherry-pick.  +* Applying: Document "git cherry-pick" and "git revert"  +First trying simple merge strategy to cherry-pick.  +Finished one cherry-pick.  +* Applying: mailinfo and applymbox updates  +First trying simple merge strategy to cherry-pick.  +Finished one cherry-pick.  +* Applying: Show commits in topo order and name all commits.  +First trying simple merge strategy to cherry-pick.  +Finished one cherry-pick.  +* Applying: More documentation updates.  +First trying simple merge strategy to cherry-pick.  +Finished one cherry-pick.</tt></pre>  +</div></div>  +<p>The temporary tag <em>pu-anchor</em> is me just being careful, in case <em>git  +rebase</em> screws up. After this, I can do these for sanity check:</p>  +<div class="listingblock">  +<div class="content">  +<pre><tt>$ git diff pu-anchor..pu ;# make sure we got the master fix.  +$ make CC=gcc-2.95 clean test ;# make sure it fixed the breakage.  +$ make clean test ;# make sure it did not cause other breakage.</tt></pre>  +</div></div>  +<p>Everything is in the good order. I do not need the temporary branch  +nor tag anymore, so remove them:</p>  +<div class="listingblock">  +<div class="content">  +<pre><tt>$ rm -f .git/refs/tags/pu-anchor  +$ git branch -d revert-c99</tt></pre>  +</div></div>  +<p>It was an emergency fix, so we might as well merge it into the  +<em>release candidate</em> branch, although I expect the next release would  +be some days off:</p>  +<div class="listingblock">  +<div class="content">  +<pre><tt>$ git checkout rc  +$ git pull . master  +Packing 0 objects  +Unpacking 0 objects  +  +* committish: e3a693c... refs/heads/master from .  +Trying to merge e3a693c... into 8c1f5f0... using 10d781b...  +Committed merge 7fb9b7262a1d1e0a47bbfdcbbcf50ce0635d3f8f  + cache.h | 8 ++++----  + commit.c | 2 +-  + ls-files.c | 2 +-  + receive-pack.c | 2 +-  + server-info.c | 2 +-  + 5 files changed, 8 insertions(+), 8 deletions(-)</tt></pre>  +</div></div>  +<p>And the final repository status looks like this:</p>  +<div class="listingblock">  +<div class="content">  +<pre><tt>$ git show-branch --more=1 master pu rc  +! [master] Revert "Replace zero-length array decls with []."  + ! [pu] git-repack: Add option to repack all objects.  + * [rc] Merge refs/heads/master from .  +---  + + [pu] git-repack: Add option to repack all objects.  + + [pu~1] More documentation updates.  + + [pu~2] Show commits in topo order and name all commits.  + + [pu~3] mailinfo and applymbox updates  + + [pu~4] Document "git cherry-pick" and "git revert"  + + [pu~5] Remove git-apply-patch-script.  + + [pu~6] Redo "revert" using three-way merge machinery.  + + [rc] Merge refs/heads/master from .  ++++ [master] Revert "Replace zero-length array decls with []."  + + [rc~1] Merge refs/heads/master from .  ++++ [master~1] Merge refs/heads/portable from http://www.cs.berkeley....</tt></pre>  +</div></div>  +</div>  +</div>  +<div id="footer">  +<div id="footer-text">  +Last updated 27-Dec-2005 00:17:13 PDT  +</div>  +</div>  +</body>  +</html>  
diff --git a/howto/revert-branch-rebase.txt b/howto/revert-branch-rebase.txt new file mode 100644 index 0000000..5a7e0cf --- /dev/null +++ b/howto/revert-branch-rebase.txt 
@@ -0,0 +1,200 @@ +From: Junio C Hamano <junkio@cox.net> +To: git@vger.kernel.org +Subject: [HOWTO] Reverting an existing commit +Abstract: In this article, JC gives a small real-life example of using + 'git revert' command, and using a temporary branch and tag for safety + and easier sanity checking. +Date: Mon, 29 Aug 2005 21:39:02 -0700 +Content-type: text/asciidoc +Message-ID: <7voe7g3uop.fsf@assigned-by-dhcp.cox.net> + +Reverting an existing commit +============================ + +One of the changes I pulled into the 'master' branch turns out to +break building GIT with GCC 2.95. While they were well intentioned +portability fixes, keeping things working with gcc-2.95 was also +important. Here is what I did to revert the change in the 'master' +branch and to adjust the 'pu' branch, using core GIT tools and +barebone Porcelain. + +First, prepare a throw-away branch in case I screw things up. + +------------------------------------------------ +$ git checkout -b revert-c99 master +------------------------------------------------ + +Now I am on the 'revert-c99' branch. Let's figure out which commit to +revert. I happen to know that the top of the 'master' branch is a +merge, and its second parent (i.e. foreign commit I merged from) has +the change I would want to undo. Further I happen to know that that +merge introduced 5 commits or so: + +------------------------------------------------ +$ git show-branch --more=4 master master^2 | head +! [master] Merge refs/heads/portable from http://www.cs.berkeley.... + ! [master^2] Replace C99 array initializers with code. +-- ++ [master] Merge refs/heads/portable from http://www.cs.berkeley.... +++ [master^2] Replace C99 array initializers with code. +++ [master^2~1] Replace unsetenv() and setenv() with older putenv(). +++ [master^2~2] Include sys/time.h in daemon.c. +++ [master^2~3] Fix ?: statements. +++ [master^2~4] Replace zero-length array decls with []. ++ [master~1] tutorial note about git branch +------------------------------------------------ + +The '--more=4' above means "after we reach the merge base of refs, +show until we display four more common commits". That last commit +would have been where the "portable" branch was forked from the main +git.git repository, so this would show everything on both branches +since then. I just limited the output to the first handful using +'head'. + +Now I know 'master^2~4' (pronounce it as "find the second parent of +the 'master', and then go four generations back following the first +parent") is the one I would want to revert. Since I also want to say +why I am reverting it, the '-n' flag is given to 'git revert'. This +prevents it from actually making a commit, and instead 'git revert' +leaves the commit log message it wanted to use in '.msg' file: + +------------------------------------------------ +$ git revert -n master^2~4 +$ cat .msg +Revert "Replace zero-length array decls with []." + +This reverts 6c5f9baa3bc0d63e141e0afc23110205379905a4 commit. +$ git diff HEAD ;# to make sure what we are reverting makes sense. +$ make CC=gcc-2.95 clean test ;# make sure it fixed the breakage. +$ make clean test ;# make sure it did not cause other breakage. +------------------------------------------------ + +The reverted change makes sense (from reading the 'diff' output), does +fix the problem (from 'make CC=gcc-2.95' test), and does not cause new +breakage (from the last 'make test'). I'm ready to commit: + +------------------------------------------------ +$ git commit -a -s ;# read .msg into the log, + # and explain why I am reverting. +------------------------------------------------ + +I could have screwed up in any of the above steps, but in the worst +case I could just have done 'git checkout master' to start over. +Fortunately I did not have to; what I have in the current branch +'revert-c99' is what I want. So merge that back into 'master': + +------------------------------------------------ +$ git checkout master +$ git resolve master revert-c99 fast ;# this should be a fast forward +Updating from 10d781b9caa4f71495c7b34963bef137216f86a8 to e3a693c... + cache.h | 8 ++++---- + commit.c | 2 +- + ls-files.c | 2 +- + receive-pack.c | 2 +- + server-info.c | 2 +- + 5 files changed, 8 insertions(+), 8 deletions(-) +------------------------------------------------ + +The 'fast' in the above 'git resolve' is not a magic. I knew this +'resolve' would result in a fast forward merge, and if not, there is +something very wrong (so I would do 'git reset' on the 'master' branch +and examine the situation). When a fast forward merge is done, the +message parameter to 'git resolve' is discarded, because no new commit +is created. You could have said 'junk' or 'nothing' there as well. + +There is no need to redo the test at this point. We fast forwarded +and we know 'master' matches 'revert-c99' exactly. In fact: + +------------------------------------------------ +$ git diff master..revert-c99 +------------------------------------------------ + +says nothing. + +Then we rebase the 'pu' branch as usual. + +------------------------------------------------ +$ git checkout pu +$ git tag pu-anchor pu +$ git rebase master +* Applying: Redo "revert" using three-way merge machinery. +First trying simple merge strategy to cherry-pick. +Finished one cherry-pick. +* Applying: Remove git-apply-patch-script. +First trying simple merge strategy to cherry-pick. +Simple cherry-pick fails; trying Automatic cherry-pick. +Removing Documentation/git-apply-patch-script.txt +Removing git-apply-patch-script +Finished one cherry-pick. +* Applying: Document "git cherry-pick" and "git revert" +First trying simple merge strategy to cherry-pick. +Finished one cherry-pick. +* Applying: mailinfo and applymbox updates +First trying simple merge strategy to cherry-pick. +Finished one cherry-pick. +* Applying: Show commits in topo order and name all commits. +First trying simple merge strategy to cherry-pick. +Finished one cherry-pick. +* Applying: More documentation updates. +First trying simple merge strategy to cherry-pick. +Finished one cherry-pick. +------------------------------------------------ + +The temporary tag 'pu-anchor' is me just being careful, in case 'git +rebase' screws up. After this, I can do these for sanity check: + +------------------------------------------------ +$ git diff pu-anchor..pu ;# make sure we got the master fix. +$ make CC=gcc-2.95 clean test ;# make sure it fixed the breakage. +$ make clean test ;# make sure it did not cause other breakage. +------------------------------------------------ + +Everything is in the good order. I do not need the temporary branch +nor tag anymore, so remove them: + +------------------------------------------------ +$ rm -f .git/refs/tags/pu-anchor  +$ git branch -d revert-c99 +------------------------------------------------ + +It was an emergency fix, so we might as well merge it into the +'release candidate' branch, although I expect the next release would +be some days off: + +------------------------------------------------ +$ git checkout rc +$ git pull . master +Packing 0 objects +Unpacking 0 objects + +* committish: e3a693c...	refs/heads/master from . +Trying to merge e3a693c... into 8c1f5f0... using 10d781b... +Committed merge 7fb9b7262a1d1e0a47bbfdcbbcf50ce0635d3f8f + cache.h | 8 ++++---- + commit.c | 2 +- + ls-files.c | 2 +- + receive-pack.c | 2 +- + server-info.c | 2 +- + 5 files changed, 8 insertions(+), 8 deletions(-) +------------------------------------------------ + +And the final repository status looks like this: + +------------------------------------------------ +$ git show-branch --more=1 master pu rc +! [master] Revert "Replace zero-length array decls with []." + ! [pu] git-repack: Add option to repack all objects. + * [rc] Merge refs/heads/master from . +--- + + [pu] git-repack: Add option to repack all objects. + + [pu~1] More documentation updates. + + [pu~2] Show commits in topo order and name all commits. + + [pu~3] mailinfo and applymbox updates + + [pu~4] Document "git cherry-pick" and "git revert" + + [pu~5] Remove git-apply-patch-script. + + [pu~6] Redo "revert" using three-way merge machinery. + + [rc] Merge refs/heads/master from . ++++ [master] Revert "Replace zero-length array decls with []." + + [rc~1] Merge refs/heads/master from . ++++ [master~1] Merge refs/heads/portable from http://www.cs.berkeley.... +------------------------------------------------ 
diff --git a/howto/update-hook-example.txt b/howto/update-hook-example.txt new file mode 100644 index 0000000..3a33696 --- /dev/null +++ b/howto/update-hook-example.txt 
@@ -0,0 +1,172 @@ +From: Junio C Hamano <junkio@cox.net> and Carl Baldwin <cnb@fc.hp.com> +Subject: control access to branches. +Date: Thu, 17 Nov 2005 23:55:32 -0800 +Message-ID: <7vfypumlu3.fsf@assigned-by-dhcp.cox.net> +Abstract: An example hooks/update script is presented to + implement repository maintenance policies, such as who can push + into which branch and who can make a tag. + +When your developer runs git-push into the repository, +git-receive-pack is run (either locally or over ssh) as that +developer, so is hooks/update script. Quoting from the relevant +section of the documentation: + + Before each ref is updated, if $GIT_DIR/hooks/update file exists + and executable, it is called with three parameters: + + $GIT_DIR/hooks/update refname sha1-old sha1-new + + The refname parameter is relative to $GIT_DIR; e.g. for the + master head this is "refs/heads/master". Two sha1 are the + object names for the refname before and after the update. Note + that the hook is called before the refname is updated, so either + sha1-old is 0{40} (meaning there is no such ref yet), or it + should match what is recorded in refname. + +So if your policy is (1) always require fast-forward push +(i.e. never allow "git-push repo +branch:branch"), (2) you +have a list of users allowed to update each branch, and (3) you +do not let tags to be overwritten, then you can use something +like this as your hooks/update script. + +[jc: editorial note. This is a much improved version by Carl +since I posted the original outline] + +-- >8 -- beginning of script -- >8 -- + +#!/bin/bash + +umask 002 + +# If you are having trouble with this access control hook script +# you can try setting this to true. It will tell you exactly +# why a user is being allowed/denied access. + +verbose=false + +# Default shell globbing messes things up downstream +GLOBIGNORE=* + +function grant { + $verbose && echo >&2 "-Grant-	$1" + echo grant + exit 0 +} + +function deny { + $verbose && echo >&2 "-Deny-	$1" + echo deny + exit 1 +} + +function info { + $verbose && echo >&2 "-Info-	$1" +} + +# Implement generic branch and tag policies. +# - Tags should not be updated once created. +# - Branches should only be fast-forwarded. +case "$1" in + refs/tags/*) + [ -f "$GIT_DIR/$1" ] && + deny >/dev/null "You can't overwrite an existing tag" + ;; + refs/heads/*) + # No rebasing or rewinding + if expr "$2" : '0*$' >/dev/null; then + info "The branch '$1' is new..." + else + # updating -- make sure it is a fast forward + mb=$(git-merge-base "$2" "$3") + case "$mb,$2" in + "$2,$mb") info "Update is fast-forward" ;; + *) deny >/dev/null "This is not a fast-forward update." ;; + esac + fi + ;; + *) + deny >/dev/null \ + "Branch is not under refs/heads or refs/tags. What are you trying to do?" + ;; +esac + +# Implement per-branch controls based on username +allowed_users_file=$GIT_DIR/info/allowed-users +username=$(id -u -n) +info "The user is: '$username'" + +if [ -f "$allowed_users_file" ]; then + rc=$(cat $allowed_users_file | grep -v '^#' | grep -v '^$' | + while read head_pattern user_patterns; do + matchlen=$(expr "$1" : "$head_pattern") + if [ "$matchlen" == "${#1}" ]; then + info "Found matching head pattern: '$head_pattern'" + for user_pattern in $user_patterns; do + info "Checking user: '$username' against pattern: '$user_pattern'" + matchlen=$(expr "$username" : "$user_pattern") + if [ "$matchlen" == "${#username}" ]; then + grant "Allowing user: '$username' with pattern: '$user_pattern'" + fi + done + deny "The user is not in the access list for this branch" + fi + done + ) + case "$rc" in + grant) grant >/dev/null "Granting access based on $allowed_users_file" ;; + deny) deny >/dev/null "Denying access based on $allowed_users_file" ;; + *) ;; + esac +fi + +allowed_groups_file=$GIT_DIR/info/allowed-groups +groups=$(id -G -n) +info "The user belongs to the following groups:" +info "'$groups'" + +if [ -f "$allowed_groups_file" ]; then + rc=$(cat $allowed_groups_file | grep -v '^#' | grep -v '^$' | + while read head_pattern group_patterns; do + matchlen=$(expr "$1" : "$head_pattern") + if [ "$matchlen" == "${#1}" ]; then + info "Found matching head pattern: '$head_pattern'" + for group_pattern in $group_patterns; do + for groupname in $groups; do + info "Checking group: '$groupname' against pattern: '$group_pattern'" + matchlen=$(expr "$groupname" : "$group_pattern") + if [ "$matchlen" == "${#groupname}" ]; then + grant "Allowing group: '$groupname' with pattern: '$group_pattern'" + fi + done + done + deny "None of the user's groups are in the access list for this branch" + fi + done + ) + case "$rc" in + grant) grant >/dev/null "Granting access based on $allowed_groups_file" ;; + deny) deny >/dev/null "Denying access based on $allowed_groups_file" ;; + *) ;; + esac +fi + +deny >/dev/null "There are no more rules to check. Denying access" + +-- >8 -- end of script -- >8 -- + +This uses two files, $GIT_DIR/info/allowed-users and +allowed-groups, to describe which heads can be pushed into by +whom. The format of each file would look like this: + +	refs/heads/master	junio + refs/heads/cogito$	pasky +	refs/heads/bw/	linus + refs/heads/tmp/	* + refs/tags/v[0-9]*	junio + +With this, Linus can push or create "bw/penguin" or "bw/zebra" +or "bw/panda" branches, Pasky can do only "cogito", and JC can +do master branch and make versioned tags. And anybody can do +tmp/blah branches. + +------------ 
diff --git a/howto/using-topic-branches.txt b/howto/using-topic-branches.txt new file mode 100644 index 0000000..b3d592f --- /dev/null +++ b/howto/using-topic-branches.txt 
@@ -0,0 +1,288 @@ +Date: Mon, 15 Aug 2005 12:17:41 -0700 +From: tony.luck@intel.com +Subject: Some tutorial text (was git/cogito workshop/bof at linuxconf au?) +Abstract: In this article, Tony Luck discusses how he uses GIT + as a Linux subsystem maintainer. + +Here's something that I've been putting together on how I'm using +GIT as a Linux subsystem maintainer. + +-Tony + +Last updated w.r.t. GIT 0.99.9f + +Linux subsystem maintenance using GIT +------------------------------------- + +My requirements here are to be able to create two public trees: + +1) A "test" tree into which patches are initially placed so that they +can get some exposure when integrated with other ongoing development. +This tree is available to Andrew for pulling into -mm whenever he wants. + +2) A "release" tree into which tested patches are moved for final +sanity checking, and as a vehicle to send them upstream to Linus +(by sending him a "please pull" request.) + +Note that the period of time that each patch spends in the "test" tree +is dependent on the complexity of the change. Since GIT does not support +cherry picking, it is not practical to simply apply all patches to the +test tree and then pull to the release tree as that would leave trivial +patches blocked in the test tree waiting for complex changes to accumulate +enough test time to graduate. + +Back in the BitKeeper days I achieved this by creating small forests of +temporary trees, one tree for each logical grouping of patches, and then +pulling changes from these trees first to the test tree, and then to the +release tree. At first I replicated this in GIT, but then I realised +that I could so this far more efficiently using branches inside a single +GIT repository. + +So here is the step-by-step guide how this all works for me. + +First create your work tree by cloning Linus's public tree: + + $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git work + +Change directory into the cloned tree you just created + + $ cd work + +Set up a remotes file so that you can fetch the latest from Linus' master +branch into a local branch named "linus": + + $ cat > .git/remotes/linus + URL: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git + Pull: master:linus + ^D + +and create the linus branch: + + $ git branch linus + +The "linus" branch will be used to track the upstream kernel. To update it, +you simply run: + + $ git fetch linus + +you can do this frequently (and it should be safe to do so with pending +work in your tree, but perhaps not if you are in mid-merge). + +If you need to keep track of other public trees, you can add remote branches +for them too: + + $ git branch another + $ cat > .git/remotes/another + URL: ... insert URL here ... + Pull: name-of-branch-in-this-remote-tree:another + ^D + +and run: + + $ git fetch another + +Now create the branches in which you are going to work, these start +out at the current tip of the linus branch. + + $ git branch test linus + $ git branch release linus + +These can be easily kept up to date by merging from the "linus" branch: + + $ git checkout test && git merge "Auto-update from upstream" test linus + $ git checkout release && git merge "Auto-update from upstream" release linus + +Set up so that you can push upstream to your public tree (you need to +log-in to the remote system and create an empty tree there before the +first push). + + $ cat > .git/remotes/mytree + URL: master.kernel.org:/pub/scm/linux/kernel/git/aegl/linux-2.6.git + Push: release + Push: test + ^D + +and the push both the test and release trees using: + + $ git push mytree + +or push just one of the test and release branches using: + + $ git push mytree test +or + $ git push mytree release + +Now to apply some patches from the community. Think of a short +snappy name for a branch to hold this patch (or related group of +patches), and create a new branch from the current tip of the +linus branch: + + $ git checkout -b speed-up-spinlocks linus + +Now you apply the patch(es), run some tests, and commit the change(s). If +the patch is a multi-part series, then you should apply each as a separate +commit to this branch. + + $ ... patch ... test ... commit [ ... patch ... test ... commit ]* + +When you are happy with the state of this change, you can pull it into the +"test" branch in preparation to make it public: + + $ git checkout test && git merge "Pull speed-up-spinlock changes" test speed-up-spinlocks + +It is unlikely that you would have any conflicts here ... but you might if you +spent a while on this step and had also pulled new versions from upstream. + +Some time later when enough time has passed and testing done, you can pull the +same branch into the "release" tree ready to go upstream. This is where you +see the value of keeping each patch (or patch series) in its own branch. It +means that the patches can be moved into the "release" tree in any order. + + $ git checkout release && git merge "Pull speed-up-spinlock changes" release speed-up-spinlocks + +After a while, you will have a number of branches, and despite the +well chosen names you picked for each of them, you may forget what +they are for, or what status they are in. To get a reminder of what +changes are in a specific branch, use: + + $ git-whatchanged branchname ^linus | git-shortlog + +To see whether it has already been merged into the test or release branches +use: + + $ git-rev-list branchname ^test +or + $ git-rev-list branchname ^release + +[If this branch has not yet been merged you will see a set of SHA1 values +for the commits, if it has been merged, then there will be no output] + +Once a patch completes the great cycle (moving from test to release, then +pulled by Linus, and finally coming back into your local "linus" branch) +the branch for this change is no longer needed. You detect this when the +output from: + + $ git-rev-list branchname ^linus + +is empty. At this point the branch can be deleted: + + $ git branch -d branchname + +Some changes are so trivial that it is not necessary to create a separate +branch and then merge into each of the test and release branches. For +these changes, just apply directly to the "release" branch, and then +merge that into the "test" branch. + +To create diffstat and shortlog summaries of changes to include in a "please +pull" request to Linus you can use: + + $ git-whatchanged -p release ^linus | diffstat -p1 +and + $ git-whatchanged release ^linus | git-shortlog + + +Here are some of the scripts that I use to simplify all this even further. + +==== update script ==== +# Update a branch in my GIT tree. If the branch to be updated +# is "linus", then pull from kernel.org. Otherwise merge local +# linus branch into test|release branch + +case "$1" in +test|release) +	git checkout $1 && git merge "Auto-update from upstream" $1 linus +	;; +linus) +	before=$(cat .git/refs/heads/linus) +	git fetch linus +	after=$(cat .git/refs/heads/linus) +	if [ $before != $after ] +	then +	git-whatchanged $after ^$before | git-shortlog +	fi +	;; +*) +	echo "Usage: $0 linus|test|release" 1>&2 +	exit 1 +	;; +esac + +==== merge script ==== +# Merge a branch into either the test or release branch + +pname=$0 + +usage() +{ +	echo "Usage: $pname branch test|release" 1>&2 +	exit 1 +} + +if [ ! -f .git/refs/heads/"$1" ] +then +	echo "Can't see branch <$1>" 1>&2 +	usage +fi + +case "$2" in +test|release) +	if [ $(git-rev-list $1 ^$2 | wc -c) -eq 0 ] +	then +	echo $1 already merged into $2 1>&2 +	exit 1 +	fi +	git checkout $2 && git merge "Pull $1 into $2 branch" $2 $1 +	;; +*) +	usage +	;; +esac + +==== status script ==== +# report on status of my ia64 GIT tree + +gb=$(tput setab 2) +rb=$(tput setab 1) +restore=$(tput setab 9) + +if [ `git-rev-list release ^test | wc -c` -gt 0 ] +then +	echo $rb Warning: commits in release that are not in test $restore +	git-whatchanged release ^test +fi + +for branch in `ls .git/refs/heads` +do +	if [ $branch = linus -o $branch = test -o $branch = release ] +	then +	continue +	fi + +	echo -n $gb ======= $branch ====== $restore " " +	status= +	for ref in test release linus +	do +	if [ `git-rev-list $branch ^$ref | wc -c` -gt 0 ] +	then +	status=$status${ref:0:1} +	fi +	done +	case $status in +	trl) +	echo $rb Need to pull into test $restore +	;; +	rl) +	echo "In test" +	;; +	l) +	echo "Waiting for linus" +	;; +	"") +	echo $rb All done $restore +	;; +	*) +	echo $rb "<$status>" $restore +	;; +	esac +	git-whatchanged $branch ^linus | git-shortlog +done